Map = class('Map'):include(Stateful)

-- a map is any generated grid
function Map:initialize(w, h)

	self.w = w or 256
	self.h = h or 256
	self.x = 0
	self.y = 0
	self.tile_width = 16
	self.tile_height = 16
	self.view_width = love.window.getWidth()
	self.view_height = love.window.getHeight()
	self.scale = 4
	self.scroll_speed = 1000
	self.jungle_start = 512
	self.jungle_end = 3104
	self.jungle_height = self.h-94
	self.jungle_width = self.w
	self.base_height = 32
	self.nature_base = loader.load("nature_base.tmx")
	self.tech_base = loader.load("tech_base.tmx")
	self:set_spawn_points()
	self.tile_sets = {}
	self.tile_sets.jungle_tiles = love.graphics.newImage('assets/tilesets/jungle_tiles.png')
	self.tile_sets.land_obs = love.graphics.newImage('assets/tilesets/land_obstacles2.png')
	self.tile_sets.water_obs = love.graphics.newImage('assets/tilesets/water_obstacles.png')
	self.jungle = tmap:new("jungle", 
		self.jungle_width, self.jungle_height, 
		self.tile_width, self.tile_height, nil, '',
		{ 	["atl_offsetY"] = -496,
			["atl_offsetX"] = 16 })

	self.jungle.jungle_tiles = self.jungle:newTileSet(self.tile_sets.jungle_tiles, 
		'assets/tilesets/jungle_tiles.png', 'jungle_tiles',
		self.tile_width, self.tile_height, 192, 16, 1, nil, nil, nil, nil, nil, { 
		[8] = { ["water"] = true}
		} )
	self.jungle.land_obs = self.jungle:newTileSet(self.tile_sets.land_obs, 'assets/tilesets/land_obstacles2.png', 'land_obs',
		self.tile_width, self.tile_height, 48, 16, 13, nil, nil, nil, nil, nil, {
		[13] = {["collider"] = true, ["tree"] = true},
		[14] = {["collider"] = true, ["tree"] = true},
		[15] = {["collider"] = true, ["tree"] = true}
		})
	self.jungle.water_obs = self.jungle:newTileSet(self.tile_sets.water_obs, 'assets/tilesets/water_obstacles.png', 'water_obs',
		self.tile_width, self.tile_height, 16, 16, 16, nil, nil, nil, nil, nil,
		{ [16] = {["collider"] = true}
		} )
	self.jungle.ground = self.jungle:newTileLayer(1, "ground")
	self.jungle.ground_decor = self.jungle:newTileLayer(1, "ground_decor")

	self.wall_types = { 13, 14, 15 }
	self.floor_types = { 3, 4, 5, 6 }
	self.reps = 5
	self.reps2 = 3

	--self.jungle.ground:set(1, 1, self.jungle.tiles[1])
	self:jungle_build_thread()
	
	

end

function Map:set_spawn_points()
	local tml = self.tech_base.layers["zones"].objects
	local nml = self.nature_base.layers["zones"].objects
	local tx, ty, nx, ny
	local ts, ns = false, false
	for i = 1, #tml do
		if tml[i].properties.spawn and ts == false then
			local vx = tml[i].x + (tml[i].width/2) 
			local vy = tml[i].y + (tml[i].height/2) + self.jungle_end
			tx = (math.floor(vx/self.tile_width)*self.tile_width)+10
			ty = (math.floor(vy/self.tile_height)*self.tile_height)+10
			ts = true
		end
	end

	for i = 1, #nml do
		if nml[i].properties.spawn and ns == false then
			nx = math.floor(nml[i].x + (nml[i].width/2))
			ny = math.floor(nml[i].y + (nml[i].height/2))
			ns = true
		end
	end

	self.nature_spawn = {}
	self.nature_spawn.x = nx
	self.nature_spawn.y = ny

	self.tech_spawn = {}
	self.tech_spawn.x = tx
	self.tech_spawn.y = ty

	local nsp = love.thread.getChannel("nature_spawn")
	local tsp = love.thread.getChannel("tech_spawn")
	nsp:push(self.nature_spawn)
	tsp:push(self.tech_spawn)

end

function Map:set_collision_data()
	local ccn = love.thread.getChannel("nature_collision_data")
	local ccj = love.thread.getChannel("jungle_collision_data")
	local cct = love.thread.getChannel("tech_collision_data")

	local nat_col = {}
	local jun_col = {}
	local tech_col = {}

	for y = 1, self.base_height do
		for x = 1, self.w do
			local nt = self.nature_base.layers["structure"]:get(x, y)
			local tt = self.tech_base.layers["structure"]:get(x, y)

			if nt and nt.properties and nt.properties.collider then
				nat_col[self.w*(y-1)+x] = 1
			else
				nat_col[self.w*(y-1)+x] = 0
			end

			if tt and tt.properties and tt.properties.collider then
				tech_col[self.w*(y-1)+x] = 1
			else
				tech_col[self.w*(y-1)+x] = 0
			end	

		end
	end

	for y = 1, self.jungle_height do
		for x = 1, self.jungle_width do
			local jt = self.jungle.layers["ground_decor"]:get(x,y)

			if jt and jt.properties and jt.properties.collider then
				jun_col[self.jungle_width*(y-1)+x] = 1
			else
				jun_col[self.jungle_width*(y-1)+x] = 0
			end
		end
	end

	ccn:push(nat_col)
	ccj:push(jun_col)
	cct:push(tech_col)

end

function Map:move(x, y, dt)
	local x1 = x or 0
	local y1 = y or 0

	self.x = self.x + (x*(self.scroll_speed*dt))
	self.y = self.y + (y*(self.scroll_speed*dt))
end

function Map:zoom(amount)
	if amount then
		self.scale = self.scale*amount
	else
		self.scale = 1
	end
end

function Map:mousePosition()
  return love.mouse.getX() * self.scale + self.x, love.mouse.getY() * self.scale + self.y
end

function Map:draw()
	local ftx, fty = math.floor(self.x), math.floor(self.y)
	love.graphics.push()
	love.graphics.scale(self.scale)
	love.graphics.translate(-ftx, -fty)
	self.nature_base:setDrawRange(ftx, fty, ftx+(self.view_width/self.scale), fty+(self.view_height/self.scale))	
	self.nature_base:draw()	
	if self.scale < 1 then
		self.tech_base:setDrawRange(ftx, fty-(self.jungle_end/self.scale), 
			ftx+(self.view_width/self.scale), fty+(self.view_height/self.scale))	
		self.jungle:setDrawRange(ftx, fty-(self.jungle_start/self.scale), 
			ftx+(self.view_width/self.scale), fty+(self.view_height/self.scale))
	elseif self.scale > 1 then
		self.tech_base:setDrawRange(ftx, fty-(self.jungle_end*self.scale), 
			ftx+(self.view_width/self.scale), fty+(self.view_height/self.scale))	
		self.jungle:setDrawRange(ftx, fty-(self.jungle_start*self.scale), 
			ftx+(self.view_width/self.scale), fty+(self.view_height/self.scale))
	else
		self.tech_base:setDrawRange(ftx, fty-(self.jungle_end*self.scale*2), 
			ftx+(self.view_width/self.scale), fty+(self.view_height/self.scale))	
		self.jungle:setDrawRange(ftx, fty-(self.jungle_start*self.scale*2), 
			ftx+(self.view_width/self.scale), fty+(self.view_height/self.scale))
	end
	self.tech_base:draw()

	
	self.jungle:draw()
	love.graphics.pop()
end

function Map:update(dt, controls)
	if love.keyboard.isDown(unpack(controls.camera_up)) then
		self:move(0, -1, dt)
	end

	if love.keyboard.isDown(unpack(controls.camera_down)) then
		self:move(0, 1, dt)
	end

	if love.keyboard.isDown(unpack(controls.camera_right)) then
		self:move(1, 0, dt)
	end

	if love.keyboard.isDown(unpack(controls.camera_left)) then
		self:move(-1, 0, dt)
	end

	local jm = love.thread.getChannel("jungle_map")

	if jm:peek() then
		local jmap = jm:pop()		
		self:parse_jmap(jmap)

	end

	local cc = love.thread.getChannel("collision_check")
	if cc:peek() then
		local c = cc:pop()
		local ip, x, y = self:parse_collision(c)
	end
end

function Map:parse_collision(c)
	print(c)
	local ip, x, y, ax, ay = c:match("(.+),(%d+),(%d+),(%d+),(%d+)")
	print("collision parsed .. ", ip, x, y, ax, ay)
	

end

function Map:controls(key, isRepeat)
	if key == "kp+" then
		self:zoom(2)
	elseif key == "kp-" then
		self:zoom(0.5)
	elseif key == "kpenter" then
		self:zoom()
	end
end

function Map:jungle_build_thread()
	self.jungle_thread = love.thread.newThread('src/threads/jungle_builder.lua')
	self.jungle_thread:start()
	local cWidth = love.thread.getChannel("jungle_width")
	cWidth:push(self.jungle_width)
	local cHeight = love.thread.getChannel("jungle_height")
	cHeight:push(self.jungle_height)
	local cWallTypes = love.thread.getChannel("wall_types")
	cWallTypes:push(self.wall_types)
	local cFloorTypes = love.thread.getChannel("floor_types")
	cFloorTypes:push(self.floor_types)
	local reps = love.thread.getChannel("reps")
	reps:push(self.reps)
	local reps2 = love.thread.getChannel("reps2")
	reps2:push(self.reps2)

end

function Map:set_jungle_tile(x, y, tileNumber)
	local layer 
	if tileNumber <= 12 then
		layer = "ground"
	else
		layer = "ground_decor"
	end
	self.jungle.layers[layer]:set(x, y, self.jungle.tiles[tileNumber])
end

function Map:parse_jmap(jmap)
	local x_counter = 1
	local y_counter = 1
	--print(#jmap)
	local add_tiles = {}
	for i = 1, #jmap do
		self:set_jungle_tile(x_counter, y_counter, jmap[i])
		if x_counter == self.jungle_width then
			add_tiles[#add_tiles+1] = {
				["x"] = x_counter,
				["y"] = y_counter,
				["v"] = jmap[i]
			}
		elseif y_counter == self.jungle_height then
			add_tiles[#add_tiles+1] ={
				["x"] = x_counter,
				["y"] = y_counter,
				["v"] = jmap[i]				
			}
		end

		x_counter = x_counter+1		

		if x_counter > self.jungle_width then
			x_counter = 1
			y_counter = y_counter+1
		end

		if y_counter > self.jungle_height then
			y_counter = 1
		end
	end
	local map_string = loader.save_to_string(self.jungle)
	local extra_tiles = table.tostring(add_tiles)
	--print("extra tiles .. " .. extra_tiles)
	--print(map_string)
	local jsm = love.thread.getChannel("jungle_map_server")
	local jsme = love.thread.getChannel("jungle_extra")
	jsm:push(map_string)
	jsme:push(extra_tiles)

	self:set_collision_data()
end